from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from rest_framework.viewsets import ViewSet
from django_redis import get_redis_connection
import logging
from django.conf import settings

from course.models import Course, CourseExpire

log = logging.getLogger('django')


class CartAPIView(ViewSet):
    def add(self, request, *args, **kwargs):

        permission_classes = [IsAuthenticated, ]

        user_id = request.user.id
        course_id = request.data.get('course_id')
        is_selected = True  # 默认是选中状态
        expire = 0  # 默认为0，表示永久生效

        try:
            course = Course.objects.filter(pk=course_id, is_show=True, is_delete=False).first()
        except:
            return Response({'message': '没有你要找的课程'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            redis = get_redis_connection('cart')
            pipe = redis.pipeline()
            pipe.multi()

            # 保存商品信息到购物车中
            pipe.hset("cart_%s" % user_id, course_id, expire)
            # 保存商品勾选状态到购物车中
            pipe.sadd("selected_%s" % user_id, course_id)

            pipe.execute()
            # 获取当前用户购物车中的商品的数量
            total = redis.hlen('cart_%s' % user_id)
        except:
            log.error('购物车商品添加失败，redis操作出错！')
            return Response({"message": "商品添加失败，请联系客服工作人员！"},
                            status=status.HTTP_507_INSUFFICIENT_STORAGE)

        # 返回购物车的状态信息
        return Response({"message": "添加商品成功!", "total": total},
                        status=status.HTTP_201_CREATED)

    def list(self, request):
        """购物车商品列表"""
        """
        购物车中的商品信息和商品勾选状态是分开存储的，但是我们现在需要一个接口提供所有数据，所以我们需要整合/重构数据的结构
        cart_<user_id>:{
            <course_id>:<expire>,
            <course_id>:<expire>,
            ...
        }

        selected_<user_id>:{<course_id>,<course_id>,....}

        目标：把数据整合成一个列表，列表中每一个成员就是商品字典：
        data = [
            {
                course_id:<course_id>,
                expire:<expire>,
                selected:<selected>,
            },
            {
                course_id:<course_id>,
                expire:<expire>,
                selected:<selected>,
            },
            {
                course_id:<course_id>,
                expire:<expire>,
                selected:<selected>,
                expire_list: {
                    id: xxx,
                    expire_text: xxxx,
                }
            },
        ]
        """
        # 获取当前登录用户
        # user_id = 1  # request.user.id
        user_id = request.user.id

        # 从redis中提取当前用户的购物车信息
        redis = get_redis_connection("cart")
        # 循环购物车商品信息，重构数据
        cart_list = redis.hgetall("cart_%s" % user_id)  # {b'6': b'0', b'4': b'0', b'7': b'0', b'3': b'0'}
        selected_list = redis.smembers("selected_%s" % user_id)  # {b'7', b'3'}

        data_list = []
        for field_bytes, value_bytes in cart_list.items():
            field = int(field_bytes.decode())
            course = Course.objects.get(is_show=True, is_delete=False, pk=field)
            data_list.append({
                "course_id": field_bytes.decode(),
                "expire": value_bytes.decode(),
                "selected": field_bytes in selected_list,
                # 这里的图片是一个字段对象在模型中进行声明的，所以我们不能直接返回，而是调用这个图片对象的url属性
                "course_img": settings.CKEDITOR_UPLOAD_URL + course.course_img.url,
                "name": course.name,
                "expire_list": course.expire_list,
                "price": course.price,
                "real_price": course.real_price()
            })
        # 返回返回给客户端
        return Response(data_list, status=status.HTTP_200_OK)

    def change_selected_status(self, request):
        """切换商品额勾选状态"""
        # 接受数据[商品ID，用户ID，勾选状态]
        user_id = request.user.id
        course_id = request.data.get("course_id")
        is_selected = request.data.get("is_selected")
        try:
            course = Course.objects.get(is_show=True, is_delete=False, pk=course_id)
        except Course.DoesNotExist:
            return Response({"message": "对不起，当前商品已下架或不存在！"}, status=status.HTTP_400_BAD_REQUEST)

        # 连接redis
        try:
            redis = get_redis_connection("cart")
            # 判断客户端提交的勾选状态，增删redis中对应用户id的商品ID
            if is_selected:
                redis.sadd("selected_%s" % user_id, course_id)
            else:
                redis.srem("selected_%s" % user_id, course_id)
        except:
            log.error("redis数据库操作出错！")
            return Response({"message": "对不起，切换商品勾选状态有误！请联系客服工作人员！"}, status=status.HTTP_507_INSUFFICIENT_STORAGE)

        # 返回操作结果
        return Response({"message": "商品勾选状态切换成功！"}, status=status.HTTP_200_OK)

    def delete(self, request):
        user_id = request.user.id
        # user_id = 1
        course_id = request.query_params.get('course_id')

        try:
            course = Course.objects.get(pk=course_id)
        except:
            return Response({'message': '对不到对应的商品'}, status=status.HTTP_400_BAD_REQUEST)

        redis = get_redis_connection('cart')
        try:
            pipe = redis.pipeline()
            pipe.multi()
            # 删除hash里面的购物车商品信息
            pipe.hdel('cart_%s' % user_id, course_id)
            # 删除set里面的商品勾选状态
            pipe.srem('selected_%s' % user_id, course_id)
            pipe.execute()
        except:
            return Response({'message': 'redis服务出错'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response({'message': '删除成功'}, status=status.HTTP_200_OK)

    def put(self, request):
        """切换课程的有效期"""
        # 获取数据[user_id，course_id，有效期id]
        # user_id = 1  # request.user.id
        user_id = request.user.id
        course_id = request.data.get("course_id")
        expire_id = request.data.get("expire_id")
        try:
            course = Course.objects.get(is_show=True, is_delete=False, pk=course_id)
        except Course.DoesNotExist:
            return Response({"message": "对不起，当前商品已下架或不存在！"},
                            status=status.HTTP_400_BAD_REQUEST)

        try:
            expire = CourseExpire.objects.get(is_show=True, is_delete=False, pk=expire_id)
        except CourseExpire.DoesNotExist:
            return Response({"message": "对不起，当前商品的有效期选项不存在！"},
                            status=status.HTTP_400_BAD_REQUEST)

        # 修改redis中购物车中对应商品ID的有效期
        try:
            redis = get_redis_connection("cart")
            redis.hset("cart_%s" % user_id, course_id, expire_id)
        except:
            log.error("redis数据库操作出错！")
            return Response({"message": "对不起，切换商品有效期选项有误！请联系客服工作人员！"},
                            status=status.HTTP_507_INSUFFICIENT_STORAGE)

        # 返回结果[对应有效期的价格]
        return Response({"message": "切换商品有效期选项成功！", "price": expire.price},
                        status=status.HTTP_200_OK)

    def get_selected_course(self, request):
        """
        获取购物车中勾选的商品信息
        :param request:
        :return:
        """
        # user_id = 1 # request.user.id
        user_id = request.user.id

        try:
            # 连接redis
            redis = get_redis_connection("cart")

            # 取出被勾选的课程    集合
            course_set = redis.smembers("selected_%s" % user_id)
            # {b'4', b'5', b'3'}
            # [course_id, course_id, course_id]
            # 取出购物车里面的课程  哈希    course_id: expire
            cart_list = redis.hgetall("cart_%s" % user_id)
            # {b'4': b'0', b'3': b'0', b'5': b'0'}
        except:
            log.error("redis存储出错！")
            return Response("获取购物车商品失败！请联系客服工作人员")

        # 计算所有商品的总价
        total_price = 0
        # 创建一个空的列表用于保存商品课程列表
        course_list = []
        for course_id_bytes in course_set:
            course_expire_bytes = cart_list[course_id_bytes]
            expire_id = int(course_expire_bytes.decode())
            # 已被勾选的课程id
            course_id = int(course_id_bytes.decode())

            try:
                course = Course.objects.get(pk=course_id)
            except:
                return Response("对不起，商品课程不存在！")

            # 提取课程的有效期选项
            # if expire_id > 0:
            #     course_expire = CourseExpire.objects.get(pk=expire_id)
            #     price = course_expire.price
            # else:
            #     price = course.price
            price = course.price

            course_list.append({
                "id": course.id,
                "course_img": settings.CKEDITOR_UPLOAD_URL +course.course_img.url,
                "name": course.name,
                # "discount_name": course.discount_type,
                "expire": "永久有效",
                "price": price,
                "real_price": price,
            })

            # 记录订单总价
            total_price += price

        data = {
            "total_price": total_price,
            "course_list": course_list,
        }

        return Response(data)




